package com.fiona.remoting.netty.server;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fiona.common.exception.RemotingException;
import com.fiona.remoting.api.AbstractServer;
import com.fiona.remoting.netty.NettyChannel;
import com.fiona.remoting.netty.codec.MessageDecoder;
import com.fiona.remoting.netty.codec.MessageEncoder;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.RuntimeUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;

public class NettyServer extends AbstractServer {
	private static Logger logger = LoggerFactory.getLogger(NettyServer.class);

	private ServerBootstrap bootstrap;
	private NettyChannel nettyChannel;

	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;
	
    public NettyServer(InetSocketAddress address) throws RemotingException {
        super(address);
    }
    public static ThreadFactory createThreadFactory(String threadNamePrefix) {
        if (threadNamePrefix != null) {
        	return new ThreadFactoryBuilder().setNamePrefix(threadNamePrefix + "-%d").build();
        }
        return Executors.defaultThreadFactory();
    }
	protected void doOpen() throws Throwable {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        DefaultEventExecutorGroup serviceHandlerGroup = new DefaultEventExecutorGroup(
                RuntimeUtil.getProcessorCount() * 2,
                createThreadFactory("service-handler-group")
        );
        try {
            bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // TCP默认开启了 Nagle 算法，该算法的作用是尽可能的发送大数据快，减少网络传输。TCP_NODELAY 参数的作用就是控制是否启用 Nagle 算法。
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    // 是否开启 TCP 底层心跳机制
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //表示系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁，服务器处理创建新连接较慢，可以适当调大这个参数
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    // 当客户端第一次进行请求的时候才会进行初始化
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            // 30 秒之内没有收到客户端请求的话就关闭连接
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));
                            p.addLast(new MessageDecoder());
                            p.addLast(new MessageEncoder());
                            p.addLast(serviceHandlerGroup, new NettyServerHandler());
                        }
                    });

			ChannelFuture channelFuture = bootstrap.bind(getBindAddress().getPort());
//			channelFuture.channel().closeFuture().syncUninterruptibly();

			channelFuture.syncUninterruptibly();
			Channel channel = channelFuture.channel();
			nettyChannel = NettyChannel.getOrAddChannel(channel);

			logger.info("NettyServer:[{}]端口启动成功", getBindAddress().getPort());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			workerGroup.shutdownGracefully();
//			bossGroup.shutdownGracefully();
		}
	}

	@Override
	public void send(com.fiona.remoting.api.Channel channel, Object message) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Object received(com.fiona.remoting.api.Channel channel) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected void doClose() throws Throwable {
		// TODO Auto-generated method stub
		
	}
	

}
